//
// Created by hunan on 24-8-22.
//

#ifndef PROTOCOL_CONNECTION_H
#define PROTOCOL_CONNECTION_H

#include "./../protocol_center/protocol_parser.h"
#include "./../socket_module/socket_connection.h"

#include <functional>
#include <memory>
#include <string>

class Loop;
class ProtocolOperation;
class ProtocolConnection : public std::enable_shared_from_this<ProtocolConnection>
{
public:
    using OnConnect = std::function<void(ProtocolConnection * connection, int)>;
    using OnMessage = std::function<void(ProtocolConnection * connection, ProtocolOperation * operation)>;
    using OnConnErr = std::function<void(ProtocolConnection * connection, int)>;
    using OnDisConn = std::function<void(ProtocolConnection * connection, int)>;
    struct Option
    {
        std::string m_ssl_key_log_file;
    };
    class ProtocolConnectionObserver : public SocketObserver
    {
    public:
        explicit ProtocolConnectionObserver(ProtocolConnection * connection);
        ~ProtocolConnectionObserver() override = default;
        void Update(SocketCommand * command) override;
    private:
        ProtocolConnection * m_protocol_connection;
    };
public:
    ProtocolConnection(Loop * loop, ProtocolOperation * operation);
    ~ProtocolConnection();
    int                            InitServerUrl(const std::string & url);
    int                            InitServerUrl(const std::string & url, const Option & option);
    void                           CloseConnection();
    int                            SendMessage(const uint8_t * data, int data_length) const;
    ProtocolParser::ProtocolData & ProtocolData();
    void                           OnProtocolConnect(OnConnect && conn);
    void                           OnProtocolMessage(OnMessage && message);
    void                           OnProtocolConnErr(OnConnErr && conn_err);
    void                           OnProtocolDisConn(OnDisConn && dis_conn);
    ProtocolOperation            * GetProtocolOperation() const;
private:
    void ProcessConnected(SocketCommand  * command);
    void ProcessError(SocketCommand * command);
    void ProcessDisconnect(SocketCommand * command);
    void ProcessRead(SocketCommand       * command);
    void OnEvent(SocketCommand * command);
    int  InitServerUrl();
private:
    Loop *                            m_loop;
    ProtocolOperation *               m_protocol_operation;
    std::string                       m_url; // for dns
    struct Option                     m_options;
    ProtocolParser::ProtocolData      m_protocol_data;
    std::shared_ptr<SocketConnection> m_socket_connection;
    bool                              m_need_reconnect;
private:
    OnConnect m_connection_cb;
    OnDisConn m_disconnection_cb;
    OnConnErr m_connect_error_cb;
    OnMessage m_message_cb;
};

#endif // PROTOCOL_CONNECTION_H
